package pl.edu.agh.ssm.monitor.listeners;

import java.util.HashMap;
import java.util.LinkedList;

import jlibrtp.RtcpPkt; //import jlibrtp.RtpPkt;
//import pl.edu.agh.ssm.monitor.Controller;
//import pl.edu.agh.ssm.monitor.SessionContainer;
import pl.edu.agh.ssm.monitor.SessionMonitorApp;
import pl.edu.agh.ssm.monitor.data.Packet;
import pl.edu.agh.ssm.monitor.data.Session;
import pl.edu.agh.ssm.monitor.data.SessionDataContainer;
import pl.edu.agh.ssm.monitor.data.SessionDescription;
import pl.edu.agh.ssm.monitor.data.SessionPair;
import pl.edu.agh.ssm.monitor.data.SessionType;
//import pl.edu.agh.ssm.monitor.net.PacketFilter;
import pl.edu.agh.ssm.monitor.net.PacketReceiver;
import pl.edu.agh.ssm.monitor.parsers.rtcp.RTCPParser;
import pl.edu.agh.ssm.monitor.utils.PacketListenersUtils;

/**
 * Recognizes multimedia sessions based on RTCP, when new session is found - it
 * is added to session container and new listeners (on rtp and rtcp data) are
 * created
 * 
 * @author Tomasz Jadczyk
 * 
 */
public class RTPSessionListener implements PacketListener {

	private RTCPParser packetsParser;
//	private SessionContainer container;
	private PacketReceiver receiver;
	private int priority = 10;

	private HashMap<SessionPair, Session> foundSession;

	private SessionDataContainer<Session> sessions = null;

	public RTPSessionListener(PacketReceiver receiver) {
		packetsParser = new RTCPParser();
//		container = Controller.getInstance().getSessionContainer();
		foundSession = new HashMap<SessionPair, Session>();
		this.receiver = receiver;

		sessions = SessionMonitorApp.getApplication().getManager()
				.createContainer(Session.class);
	}

	@Override
	public void processPacket(Packet packet) {
		// Recognize only RTCP packet (error handling is available)
		if (packet.getDestPort() % 2 == 1) { // Maybe RTCP packet
			LinkedList<RtcpPkt> rtcpPackets = packetsParser.parse(packet
					.getData());
			if (!rtcpPackets.isEmpty()) {
				SessionPair pair = new SessionPair(packet.getDestAddress(),
						packet.getDestPort() - 1); // main session port is RTP
													// port (even number)
				checkAndCreateListeners(pair, packet);
			}
		}
	}

	private void checkAndCreateListeners(SessionPair pair, Packet packet) {
		Session session = foundSession.get(pair);
		session = sessions.get(pair.toString());

		if (session == null) {
			/*
			 * Create new session object and put it to own list and to container
			 */

			session = new Session(pair.toString());

			session.setSessionType(SessionType.RTP_SESSION);
			session.setSessionDesc("RTP session: "
					+ pair.getAddress().getHostAddress() + ", port: "
					+ pair.getPort());

			SessionDescription desc = new SessionDescription();
			desc.setType(SessionType.RTP_SESSION);
			desc.setDescription("RTP session: "
					+ pair.getAddress().getHostAddress() + ", port: "
					+ pair.getPort());
			session.setSessionDescription(desc);
			desc.setName("RTP Session");
			sessions.add(session);

			session.setNoParticipantsTimeStamp(System.currentTimeMillis());
			
			foundSession.put(pair, session);
//			container.addSession(session, pair);
			/*
			 * Create new listeners (rtp and rtcp data) with higher level
			 */
			new PacketListenersUtils().createRtpAndRTCPDataListeners(this,
					session, receiver, priority - 1, pair.getAddress()
							.getHostAddress(), pair.getPort(), packet, null, null, 0);
			
		}
	}

	// public void removeSession(Session session) {
	// //Remove listeners
	// receiver.removePacketListener(dataListeners.get(session));
	// receiver.removePacketListener(rtcpDataListeners.get(session));
	//		
	// //Remove Session from found and from container
	// LinkedList<SessionPair> pairs = new LinkedList<SessionPair>();
	// for(SessionPair sp : foundSession.keySet()) {
	// if(foundSession.get(sp) == session) {
	// pairs.add(sp);
	// }
	// }
	// for(SessionPair sp : pairs) {
	// foundSession.remove(sp);
	// container.removeSession(sp);
	// }
	//		
	// }

	public int getPriority() {
		return priority;
	}

	public void setPriority(int priority) {
		this.priority = priority;
	}

}
